/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bff.designtime.generator.api.VmApiGenerator;
import com.inspur.edp.bff.designtime.generator.core.VmCoreGenerator;
import com.inspur.edp.bff.designtime.generator.core.config.BffConfigGenerator;
import com.inspur.edp.bff.designtime.generator.core.rtgen.variable.FSVariableGenerator;
import com.inspur.edp.bff.designtime.generator.entity.VmEntityGenerator;
import com.inspur.edp.caf.generator.BaseGenerator;
import com.inspur.edp.caf.generator.module.ModuleGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.variable.CommonVariableEntity;
import com.inspur.edp.cef.generator.apiGenerator.CefApiGenerator;
import com.inspur.edp.cef.generator.apiGenerator.commonModel.CommonModelApiGenerator;
import com.inspur.edp.cef.generator.configGenerator.CefConfigGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.CefCoreGenerator;
import com.inspur.edp.cef.generator.coreGenerator.entityGenerator.CommonModelCoreGenerator;
import com.inspur.edp.cef.generator.entityGenerator.BaseEntityGenerator;
import com.inspur.edp.cef.generator.entityGenerator.entity.CommonModelEntityGenerator;
import com.inspur.edp.cef.generator.overall.commonModel.CommonModelGenerator;
import com.inspur.edp.cef.generator.overall.commonModel.CommonModelGeneratorContext;
import com.inspur.edp.cef.generator.repository.RepositoryGenerator;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.common.mapping.GspVoObjectSourceType;
import com.inspur.edp.jittojava.context.JitContext;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import java.util.ArrayList;

public class VmGenerator extends CommonModelGenerator {

    private String binPath;

    //  private VariableGenerator varGenerator;
    private JitContext metadataJitContext;
    private ModuleGenerator refGen;

    public VmGenerator(String path, GspMetadata metadata, boolean preGenerating,
                       ModuleGenerator refGen, JitContext metadataJitContext) {
        super(path, metadata, preGenerating, refGen, metadataJitContext);
        this.refGen = refGen;
        this.metadataJitContext = metadataJitContext;
    }

    public VmGenerator(String path, GspMetadata metadata, VmGeneratorContext genCtx,
                       String serverPath, ModuleGenerator refGenerator, JitContext metadataJITContext) {
        super(path, metadata, genCtx, refGenerator, metadataJITContext);
        refGen = refGenerator;
        metadataJitContext = metadataJITContext;
    }

    public VmGeneratorContext getContext() {
        return (VmGeneratorContext) super.getContext();
    }

    @Override
    protected boolean getHasRepository() {
        return false;
    }

    public final JitContext getMetadataJitContext() {
        return metadataJitContext;
    }

    @Override
    protected void beforeInitialize() {
        super.beforeInitialize();
        getContext().setVm((GspViewModel) metadata.getContent());
        getContext().setMetadata(metadata);
        getContext().setRefGenerator(refGen);

//        getContext().setCoreAssemblyName(getMetadataJitContext().ProjectInfoList[1].AssemblyName);
        initRefEntityCollection();

        if (getContext().getVm().getIsVirtual()) {
            getContext().setVmNamespace(getContext().getVm().getGeneratingAssembly()+"." + getContext().getVm().getCode().toLowerCase());
            getContext().setRefBizEntity(null);
            getContext().setRefTemplateBizEntity(null);
        } else {

            GspMetadata refMetadata = getContext().getMetadataPool()
                    .getMetadata(null, getContext().getVm().getMapping().getTargetMetadataId());

            if (getContext().getVm().getMainObject().getMapping().getSourceType() == GspVoObjectSourceType.BeObject) {
                getContext().setRefBizEntity(
                        (GspBusinessEntity) ((refMetadata.getContent() instanceof GspBusinessEntity)
                                ? refMetadata.getContent() : null));
                if (!DotNetToJavaStringHelper.isNullOrEmpty(getContext().getRefBizEntity().getDependentEntityId())) {
                    getContext().setRefTemplateBizEntity(
                            getContext().<GspBusinessEntity>getMetadataContent(null,
                            getContext().getVm().getMapping().getTargetMetadataId()));
                }
            } else {
//                Context.setRefQo(
//                        (QueryObject) ((refMetadata.Content instanceof QueryObject) ? refMetadata.Content
//                                : null));
            }
            getContext().setVmNamespace(getContext().getVm().getGeneratingAssembly()+"." + getContext().getVm().getCode().toLowerCase());
//            getContext().setVmNamespace(metadata.getHeader().getNameSpace() + ".Vm." + getContext().getVm().getCode());
        }

//        DataValidator.CheckForEmptyString(Context.getVmNamespace(), "vmMetadataNamespace");

        prepareBeforeGen();
//        getContext().setBinPath(Path.combine(PathTransform.GetUserProjectsRoot(), binPath));
        //把基础be生成目录和be生成目录加进来否则dll无法反射
        //AppDomain.CurrentDomain.AssemblyResolve += LoadFromSameFolder;
    }

    private void initRefEntityCollection() {
        if (getContext().getVm().getIsVirtual()) {
            return;
        }
        addRefEntity(getContext().getVm().getMapping().getTargetMetadataId());

        for (IGspCommonObject obj : getContext().getVm().getAllObjectList()) {

            GspViewObject voObject = (GspViewObject) obj;
            if (voObject.getIsVirtual()) {
                continue;
            }
            addRefEntity(voObject.getMapping().getTargetMetadataId());

            for (IGspCommonField voElement : voObject.getContainElements()) {
                if (((GspViewModelElement) voElement).getIsVirtualViewElement()) {
                    continue;
                }
                addRefEntity(((GspViewModelElement) voElement).getMapping().getTargetMetadataId());
            }
        }
    }

    private void addRefEntity(String refId) {
        GspMetadata modelMetadata = getContext().getMetadataPool().getMetadata(null, refId);
        if (getContext().getRefEntityCollection().containsKey(refId)) {
            return;
        }
        if (modelMetadata == null) {
            throw new RuntimeException(getContext().getVm().getCode() + "引用的ID为" + refId
                    + "实体没有找到，请检查元数据是否存在");
        }
        getContext().getRefEntityCollection().put(refId, modelMetadata);
    }

    private void prepareBeforeGen() {
        //①获取根目录

//        var projectInfo = ServiceManager.<IMetadataProjectService>GetService()
//                .GetMetadataProjInfo(path);
//
//        var projectPath = projectInfo.ProjectPath;
//        binPath = Path.Combine(projectPath, "bin");
    }

    //Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
    //{
    //    var assemblyName = new AssemblyName(args.Name).Name;
    //    if (!string.IsNullOrEmpty(Context.ParentGeneratePath))
    //    {
    //        var parentPath = Path.Combine(Context.ParentGeneratePath, assemblyName + ".dll");
    //        if (File.Exists(parentPath))
    //        {
    //            Assembly assembly = Assembly.LoadFrom(parentPath);
    //            return assembly;
    //        }
    //    }
    //    var assemblyPath = Path.Combine(Context.VoGeneratePath, assemblyName + ".dll");
    //    if (File.Exists(assemblyPath))
    //    {
    //        Assembly assembly = Assembly.LoadFrom(assemblyPath);
    //        return assembly;
    //    }

    //    try
    //    {
    //        return MdReflectionUtil.GetAssemblyWithoutMemory(null, assemblyName, Context.BinPath, genAbsolutePath);
    //    }
    //    catch
    //    {
    //        return null;
    //    }

    //}

    @Override
    protected CommonModelGeneratorContext createCMGenContext() {
        VmGeneratorContext tempVar = new VmGeneratorContext();
        tempVar.setPreGenerating(preGenerating);
        return tempVar;
    }

    @Override
    protected ArrayList<BaseGenerator> createCefExtendGenerators() {
        CommonVariableEntity varEntity = getContext().getVm().getVariables();
        if ((varEntity == null || varEntity.getContainElements().size() == 0) && (
            varEntity.getDtmAfterModify() == null || varEntity.getDtmAfterModify().size() == 0)) {
            return null;
        }
        ArrayList<BaseGenerator> rez = new java.util.ArrayList<BaseGenerator>();
        if (preGenerating) {
            FSVariableGenerator varGenerator = new FSVariableGenerator(path, getContext().getVm().getVariables(), getContext(),
                    preGenerating, getMetadataJitContext(), getContext()); // (Context, preGenerating);
            rez.add(varGenerator);
            getMetadataJitContext().getExtendProperty().put(getContext().getVm().getID()+"VariableGen", varGenerator);
        } else {
            FSVariableGenerator variableGenerator=((FSVariableGenerator) ((getMetadataJitContext().getExtendProperty().get(getContext().getVm().getID()+"VariableGen"))));

            CommonVariableEntity variableEntity=getContext().getVm().getVariables();
            FSVariableGenerator varGenerator = new FSVariableGenerator(path,variableEntity,getContext(),getMetadataJitContext().getMetadata(),variableGenerator.getContext(),
                    getMetadataJitContext().getCoreModuleGenerator(),getMetadataJitContext(), getContext());
            getContext().setVarGenCtx(((FSVariableGenerator) ((getMetadataJitContext().getExtendProperty().get(getContext().getVm().getID()+"VariableGen")))).getVariableGeneratorContext());
            rez.add(varGenerator);
        }

        return rez;
    }

    @Override
    protected CefCoreGenerator createCoreGenerator() {
        return createCMCoreGenerator();
    }

    @Override
    protected BaseEntityGenerator createEntityGenerator() {
        return createCMEntityGenerator();
    }

    @Override
    protected CefApiGenerator createApiGenerator() {
        return createCMApiGenerator();
    }

    protected CommonModelCoreGenerator createCMCoreGenerator() {
        return new VmCoreGenerator(getContext());
    }

    protected CommonModelEntityGenerator createCMEntityGenerator() {
        return new VmEntityGenerator(getContext());
    }

    protected CommonModelApiGenerator createCMApiGenerator() {
        return new VmApiGenerator(getContext());
    }

    @Override
    protected RepositoryGenerator getCMRepositoryGenerator() {
        return null;
    }

//    private ComGeneratorContext buildEntityComGenContext() {
//        ComGeneratorContext context = new ComGeneratorContext();
//        context.GeneratePath = Context.getVoGeneratePath();
//        context.MetadataPath = Context.MetadataPath;
//        context.Model = Context.getVm();
//        context.Namespace = Context.getVmNamespace();
//        context.ParentModel = Context.getParentVm();
//        context.ParentNamespace = Context.getParentNamespace();
//        return context;
//    }

    @Override
    protected void afterGenerate() {
        super.afterGenerate();
        //if (!preGenerating)
        //{
        //    new FsConfigGenerator(Context).Generate();
        //}
        ////CopyFile();
//        if (getContext().getPreGenerating()) {
//            new ProjectRefGenerator(metadata).Generate();
//        }
    }

    @Override
    protected CefConfigGenerator createConfigGenerator() {
        return new BffConfigGenerator(getContext());
    }

}
